﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.ServiceModel.DomainServices.Client;

namespace ExpressionSerialization
{
  [TestClass]
  public class TestRIA
  {
    Demo.Web.TestDomainContext dc = new Demo.Web.TestDomainContext();

    [TestMethod()]
    public void Expression_01()
    {
      ParameterExpression par = Expression.Parameter(typeof(Demo.Web.Product), "e");
      MemberExpression fieldName = Expression.Property(par, "Name");

      ConstantExpression ecBike = Expression.Constant("Bike");
      MethodCallExpression ex1 = Expression.Call(fieldName, typeof(String).GetMethod("Contains", new[] { typeof(string) }), ecBike);

      ConstantExpression ecMountain = Expression.Constant("Mount");
      MethodCallExpression ex2 = Expression.Call(fieldName, typeof(String).GetMethod("Contains", new[] { typeof(string) }), ecMountain);

      BinaryExpression exp = BinaryExpression.And(ex1, ex2);
      byte[] aa = exp.Serialize();


      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 2);
      }, null);
    }
    //---------------------------------------------------
    [TestMethod()]
    public void Expression_02()
    {
      Expression<Func<Demo.Web.Product, bool>>  cc = p=> p.Name ==p.Name;
      byte[] aa = cc.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 295);
      }, null);
    }
    [TestMethod()]
    public void Expression_03()
    {
      Expression<Func<Demo.Web.Product, bool>> cc = p => p.Name == p.Color;
      byte[] aa = cc.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 0);
      }, null);
    }
    [TestMethod]
    public void Expression_04()
    {
      Expression<Func<Demo.Web.Product, bool>> cc = p => (int)p.ListPrice % 2 > 0;
      byte[] aa = cc.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 150);
      }, null);
    }
    [TestMethod]
    public void Expression_05()
    {
      Expression<Func<Demo.Web.Product, bool>> cc = p => (int)p.ListPrice * 2 <= 140.1m && p.SellStartDate >= new DateTime(2003, 7, 1 );
      byte[] aa = cc.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 45);
      }, null);
    }
    [TestMethod]
    public void Expression_06()
    {
      var od2 = new DateTime(2003, 7, 1);
      Expression<Func<Demo.Web.Product, bool>> cc = p => (int)p.ListPrice * 2 <= 140.1m && p.SellStartDate >= od2;
      byte[] aa = cc.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 45);
      }, null);
    }

    [TestMethod]
    public void Expression_07()
    {
      Expression<Func<Demo.Web.Product, bool>> cc = p => p.ListPrice >= decimal.Parse("5") && p.ListPrice <= 30;
      byte[] aa = cc.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 25);
      }, null);
    }

    [TestMethod()]
    public void Expression_08()
    {
      Expression res = null;
      Expression<Func<Demo.Web.Product, bool>> cc1 = p => p.ListPrice >= decimal.Parse("5") && p.Color == "Red";
      res = res.LogicalAnd(cc1);

      Expression<Func<Demo.Web.Product, bool>> cc2 = p => p.ListPrice <= decimal.Parse("30");
      res = res.LogicalAnd(cc2);

      Expression<Func<Demo.Web.Product, bool>> cc3 = p => p.Color == "Red";
      res = res.LogicalAnd(cc3);


      byte[] aa = res.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        //Assert.AreEqual(ii, 25);
      }, null);
    }

    [TestMethod()]
    public void Expression_09()
    {
      System.Linq.Expressions.Expression expRoot = null;
      Expression<Func<Demo.Web.Product, bool>> cc;
      // Price from
      cc = p => p.ListPrice >= decimal.Parse("500.1", System.Globalization.CultureInfo.InvariantCulture);
      expRoot = expRoot.LogicalAnd(cc);

      //Price to
      cc = p => p.ListPrice <= decimal.Parse("999.9", System.Globalization.CultureInfo.InvariantCulture);
      expRoot = expRoot.LogicalAnd(cc);

      //Size from
      cc = p => p.Size >= decimal.Parse("44");
      expRoot = expRoot.LogicalAnd(cc);
      //Size from
      cc = p => p.Size <= decimal.Parse("52");
      expRoot = expRoot.LogicalAnd(cc);


      string[] bikeColors = new String[] { "Red", "Black" };
      foreach(var item in bikeColors) {
        if(!string.IsNullOrEmpty(item)) {
          //string ss = item;
          cc = p => p.Color.ToUpper().Contains(item.ToUpper());
          expRoot = expRoot.LogicalOr(cc);
        }
      }

      byte[] aa = expRoot.Serialize();

      EntityQuery<Demo.Web.Product> qq = dc.GetProductQuery(aa);
      dc.Load(qq, (p) => {
        int ii = (p.Entities as ReadOnlyCollection<Demo.Web.Product>).Count;
        Assert.AreEqual(ii, 112);
      }, null);
    }

    [TestMethod()]
    public void PartConstant()
    {
      Demo.Web.TestDomainContext dc = new Demo.Web.TestDomainContext();

      Object[] values = new object[] { "bike", Guid.NewGuid(), DateTime.Now, 123, -123, long.MaxValue, long.MinValue, 3.14D, -3.14D, 12.99M, -12.99M };// 
      foreach(var item in values) {
        ConstantExpression exp = Expression.Constant(item);
        byte[] aa = exp.Serialize();

        dc.TestSerialization(aa, (p) => {
          // -- výsledek
          byte[] vv = p.Value;
          var exp1 = ExpressionExtension.Deserialize(vv,typeof(Demo.Web.Product));
          ConstantExpression exp2 = p.UserState as ConstantExpression;

          Assert.AreEqual(exp.Type, exp2.Type, "Constant - Type");
          Assert.AreEqual(exp.NodeType, exp2.NodeType, "Constant - NodeType");
          Assert.AreEqual(exp.Value, exp2.Value, "Constant - Name");

        }, exp);
      }
    }

  }
}
